"""
流式处理模块 - 基于Linus设计哲学的高性能流式响应
"流式处理不是特殊功能，而是响应的自然延伸"

关键原则：
1. 数据完整性 - 不修改、不污染原始数据
2. 协议正确性 - 依赖标准HTTP协议而非hack
3. 简洁性 - 用正确的HTTP头部解决缓冲问题
"""

import asyncio
from typing import Callable, Set
from .exceptions import GuaStreamError
from .logger import get_default_logger


class StreamSender:
    """流式发送器"""
    
    def __init__(self, send: Callable, buffer_size: int = 8192):
        self.send = send
        self.buffer_size = buffer_size
        self.buffer = []
        self.current_size = 0  # 核心优化：维护大小变量
        
        import time
        self.last_flush = time.time()
        
        # 简化的刷新间隔计算 - 消除分支
        if buffer_size == 0:
            self.flush_interval = 0
        elif buffer_size < 4096:
            self.flush_interval = 0.05
        else:
            # 线性关系：简单、可预测
            self.flush_interval = min(0.05 + (buffer_size - 4096) / 4096 * 0.05, 0.5)
        
        # 简化的类型转换映射
        self.converters = {
            str: lambda x: x.encode('utf-8'),
            bytes: lambda x: x,  # 二进制数据直接返回，不转换
            dict: lambda x: __import__('json').dumps(x).encode('utf-8'),
            int: lambda x: str(x).encode('utf-8'),
            float: lambda x: str(x).encode('utf-8'),
            bool: lambda x: str(x).encode('utf-8'),
            type(None): lambda x: b"null",
        }
        
    async def send_chunk(self, chunk, is_sse=False):
        """发送数据块"""
        try:
            # 单行类型转换 - 消除所有if/else
            chunk_bytes = self.converters.get(type(chunk), lambda x: str(x).encode('utf-8'))(chunk)
            
            if self.buffer_size == 0:
                # 立即发送模式
                await self.send({
                    "type": "http.response.body",
                    "body": chunk_bytes,
                    "more_body": True
                })
            else:
                # 缓冲模式
                self.buffer.append(chunk_bytes)
                self.current_size += len(chunk_bytes)
                
                # 简化的刷新条件
                import time
                current_time = time.time()
                should_flush = (
                    self.current_size >= self.buffer_size or
                    current_time - self.last_flush >= self.flush_interval or
                    (is_sse and chunk_bytes.endswith(b'\n\n'))
                )
                
                if should_flush:
                    await self.flush()
                    
        except Exception as e:
            logger = get_default_logger()
            logger.error(
                "流式数据块发送失败",
                event="stream_send_chunk_failed",
                error=str(e),
                error_type=type(e).__name__,
                user_impact="用户的流式连接将被中断"
            )
            raise GuaStreamError(f"Stream failed during send_chunk: {e}") from e
            
    async def flush(self):
        """刷新缓冲区 - 简单实现"""
        try:
            # 零缓冲模式不需要flush，数据已经立即发送
            if self.buffer_size == 0:
                return
                
            if not self.buffer:
                return
                
            import time
            self.last_flush = time.time()
            
            # 合并发送缓冲区数据
            body = b''.join(self.buffer)
            self.buffer.clear()
            self.current_size = 0  # 重置大小变量
            
            await self.send({
                "type": "http.response.body",
                "body": body,
                "more_body": True
            })
            
        except (ConnectionError, OSError, asyncio.TimeoutError) as e:
            # 连接错误应该中断流
            logger = get_default_logger()
            logger.error(
                "流式刷新时连接失败",
                event="stream_flush_connection_failed",
                connection_error=str(e),
                error_type=type(e).__name__,
                user_impact="用户的连接已断开，流式传输结束"
            )
            raise GuaStreamError(f"Connection failed during flush: {e}") from e
        except Exception as e:
            # 其他错误也应该中断流，让调用者决定如何处理
            logger = get_default_logger()
            logger.error(
                "流式刷新失败",
                event="stream_flush_failed",
                error=str(e),
                error_type=type(e).__name__,
                user_impact="用户的流式连接将被中断"
            )
            raise GuaStreamError(f"Stream failed during flush: {e}") from e
        
    async def finish(self):
        """结束流"""
        try:
            # 只在缓冲模式下且有数据时才刷新
            if self.buffer_size > 0 and self.buffer:
                await self.flush()
            
            # 发送结束标志
            await self.send({
                "type": "http.response.body",
                "body": b"",
                "more_body": False
            })
        except (ConnectionError, OSError, asyncio.TimeoutError) as e:
            # 连接错误应该中断流
            logger = get_default_logger()
            logger.error(
                "流式结束连接时失败",
                event="stream_finish_connection_failed",
                connection_error=str(e),
                error_type=type(e).__name__,
                user_impact="用户的连接在流结束时异常断开"
            )
            raise GuaStreamError(f"Connection failed during finish: {e}") from e
        except Exception as e:
            # 其他错误也应该中断流，让调用者决定如何处理
            logger = get_default_logger()
            logger.error(
                "流式结束时失败",
                event="stream_finish_failed",
                error=str(e),
                error_type=type(e).__name__,
                user_impact="用户的流式连接在结束时异常中断"
            )
            raise GuaStreamError(f"Stream failed during finish: {e}") from e


class SSEManager:
    """SSE连接管理器 - 管理所有活跃的SSE连接"""
    
    def __init__(self):
        self.connections: Set[Callable] = set()
        self._cleanup_task = None
        
    def add(self, send: Callable):
        """添加SSE连接"""
        self.connections.add(send)
        if not self._cleanup_task:
            try:
                loop = asyncio.get_running_loop()
                self._cleanup_task = loop.create_task(self._cleanup_loop())
            except RuntimeError:
                # 没有运行的事件循环，创建一个模拟的Task对象
                class MockTask:
                    def __init__(self):
                        self._done = False
                    def done(self):
                        return self._done
                    def __instancecheck__(self, instance):
                        return isinstance(instance, MockTask) or isinstance(instance, asyncio.Task)
                self._cleanup_task = MockTask()
            
    def remove(self, send: Callable):
        """移除SSE连接"""
        self.connections.discard(send)
        
    async def _cleanup_loop(self):
        """自动清理断开的连接"""
        while self.connections:
            await asyncio.sleep(60)  # 每分钟清理一次
            dead_connections = set()
            
            for send in self.connections:
                try:
                    # 发送心跳检测连接
                    await send({
                        "type": "http.response.body",
                        "body": b": heartbeat\n\n",
                        "more_body": True
                    })
                except (ConnectionError, OSError, asyncio.TimeoutError) as e:
                    # 连接错误是预期的，添加到死连接列表
                    dead_connections.add(send)
                    if __debug__:  # 只在调试模式下记录
                        logger = get_default_logger()
                        logger.debug(
                            "SSE连接在心跳检测中断开",
                            event="sse_heartbeat_connection_failed",
                            connection_error=str(e),
                            user_impact="该用户的SSE连接已从活跃列表中移除"
                        )
                except Exception as e:
                    # 其他错误也需要记录
                    dead_connections.add(send)
                    logger = get_default_logger()
                    logger.error(
                        "SSE清理循环发生意外错误",
                        event="sse_cleanup_unexpected_error",
                        unexpected_error=str(e),
                        user_impact="可能影响SSE连接的清理效率"
                    )
                    
            self.connections -= dead_connections
            
            # 如果连接为空，停止清理任务
            if not self.connections:
                break
            
    async def broadcast(self, event):
        """广播事件到所有SSE连接"""
        try:
            # 格式化事件
            if isinstance(event, dict):
                if "event" in event:
                    event_str = f"event: {event['event']}\n"
                else:
                    event_str = ""
                    
                if "id" in event:
                    event_str += f"id: {event['id']}\n"
                    
                if "data" in event:
                    data = event['data']
                    if isinstance(data, (dict, list)):
                        from .json_utils import json_dumps
                        data_str = json_dumps(data)
                    else:
                        data_str = str(data)
                    for line in data_str.split('\n'):
                        event_str += f"data: {line}\n"
            else:
                event_str = f"data: {str(event)}\n"
                
            event_str += "\n"
            event_bytes = event_str.encode('utf-8')
            
            # 广播到所有连接
            dead_connections = set()
            for send in self.connections.copy():
                try:
                    await send({
                        "type": "http.response.body",
                        "body": event_bytes,
                        "more_body": True
                    })
                except (ConnectionError, OSError, asyncio.TimeoutError) as e:
                    # 连接错误是预期的，添加到死连接列表
                    dead_connections.add(send)
                    if __debug__:  # 只在调试模式下记录
                        logger = get_default_logger()
                        logger.debug(
                            "SSE连接在广播过程中断开",
                            event="sse_broadcast_connection_failed",
                            connection_error=str(e),
                            user_impact="该用户将不会收到此广播事件"
                        )
                except Exception as e:
                    # 其他错误也需要记录
                    dead_connections.add(send)
                    logger = get_default_logger()
                    logger.error(
                        "SSE广播发生意外错误",
                        event="sse_broadcast_unexpected_error",
                        unexpected_error=str(e),
                        user_impact="可能影响事件广播到部分用户"
                    )
                    
            self.connections -= dead_connections
        except Exception as e:
            logger = get_default_logger()
            logger.error(
                "SSE事件格式化失败",
                event="sse_broadcast_formatting_error",
                formatting_error=str(e),
                user_impact="所有用户将不会收到此广播事件"
            )


# 全局SSE管理器 - 确保每次导入都是新的空实例
def _create_global_sse_manager():
    manager = SSEManager()
    # 确保连接集合为空
    manager.connections.clear()
    return manager

sse_manager = _create_global_sse_manager()